package game.userinteraction;

import java.awt.event.ActionEvent;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.KeyStroke;


/**
 * This class reads the game controls out of a resource bundle. It then
 * maps Methods onto those keys.
 * 
 * @author Paul
 * @author Rob
 * 
 */
public class GameControlReader {

    private static final String ERROR_MESSAGE = "shit.";
    private ResourceBundle myKeyInstructions;
    private Object myControllable;

    /**
     * Creates an Object capable of reading out instructions
     * of key presses for a particular object.
     * 
     * @param keyInstructions The ResourceBundle containing the
     *        mapping between keys and Methods of the form "SPACE" = "jump"
     *        where jump() is the method name and spacebar is the key
     *        that will trigger the jump() method to be called in the
     *        Object specified in the other argument.
     * @param userControlled The Object whose Methods are specified
     *        in the ResourceBundle, keyInstructions.
     */
    public GameControlReader (ResourceBundle keyInstructions,
            Object userControlled) {
        myKeyInstructions = keyInstructions;
        myControllable = userControlled;
    }

    /**
     * Obtains the mapping defined in the ResourceBundle argument of the
     * constructor.
     * 
     * @return The mapping between key presses and Methods.
     * @throws SecurityException Exception.
     * @throws NoSuchMethodException Exception.
     */
    public Map<KeyStroke, Action> getKeyBindings () throws SecurityException,
            NoSuchMethodException {
        Enumeration<String> keyControls = myKeyInstructions.getKeys();
        Map<KeyStroke, Action> keyBindings = new HashMap<KeyStroke, Action>();
        while (keyControls.hasMoreElements()) {
            String keyControl = keyControls.nextElement();
            System.out.println("User" + keyControl);
            String methodName = (String) myKeyInstructions.getObject(keyControl);
            keyBindings.put(KeyStroke.getKeyStroke(keyControl),
                    findMethod(methodName));
            System.out.println(KeyStroke.getKeyStroke(keyControl));
        }
        return keyBindings;
    }

    /**
     * Searches for the correct Method.
     * 
     * @param methodName The Method's name.
     * @return An Action that will trigger invocation of
     *         the Method when the relevant key is pressed.
     * @throws SecurityException Exception.
     * @throws NoSuchMethodException Exception.
     */
    private Action findMethod (String methodName) throws SecurityException,
            NoSuchMethodException {
        Class<? extends Object> controllable = myControllable.getClass();
        final Method KEY_BOUND_METHOD = controllable.getDeclaredMethod(methodName);
        System.out.println(methodName);
        Action keyBoundAction = new AbstractAction() {

            /**
             * 
             */
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed (ActionEvent e) {
                try {
                    KEY_BOUND_METHOD.invoke(myControllable);
                }
                catch (IllegalArgumentException e1) {
                    System.err.println(ERROR_MESSAGE);
                    e1.printStackTrace();
                }
                catch (IllegalAccessException e1) {
                    System.err.println(ERROR_MESSAGE);
                    e1.printStackTrace();
                }
                catch (InvocationTargetException e1) {
                    System.err.println(ERROR_MESSAGE);
                    e1.printStackTrace();
                }

            }

        };
        return keyBoundAction;
    }
}
